<?php

namespace Newbie\Cache;

use Newbie\Abstracts\AbstractRedis;
use support\Redis as BaseRedis;

class Redis extends AbstractRedis {

    public function get (string $key, mixed $default = null): mixed {
        return BaseRedis::get($this->getKey($key)) ?? $default;
    }

    public function getBase ($key): bool|string {
        return BaseRedis::get($key);
    }

    public function delBase ($key): int {
        return BaseRedis::del($key);
    }

    /**
     * 如果不存在则写入缓存
     * @param string $name
     * @param mixed $default
     * @param int $expire
     * @param string $tag
     * @return mixed|string|null
     */
    public function remember (string $name, mixed $default = '', int $expire = 0, string $tag = 'newbie'): mixed {
        $value = BaseRedis::get($this->getKey($name));
        if ($value) {
            return $value;
        }
        $value = is_callable($default) ? $default() : $default;
        BaseRedis::set($this->getKey($name), $value, $expire);
        return $value;
    }

    public function set (string $name, mixed $value, $expireResolution = null, $ttl = null): bool {
        BaseRedis::sAdd($this->getKey('cacheKeys'), $this->getKey($name));//存放key集合
        return BaseRedis::set($this->getKey($name), $value, $expireResolution, $ttl);
    }

    public function del ($name): int {
        BaseRedis::sRem($this->getKey('cacheKeys'), $this->getKey($name));//减少key集合
        return BaseRedis::del($this->getKey($name));
    }

    public function clear (): void {
        foreach (BaseRedis::sMembers($this->getKey('cacheKeys')) as $key) {
            BaseRedis::del($key);
        }
    }

    public function setNx ($name, $value): void {
        BaseRedis::setNx($this->getKey($name), $value);
    }

    public function has (string $name): int {
        return BaseRedis::exists($this->getKey($name));
    }

    public function exists (string $name): int {
        return BaseRedis::exists($this->getKey($name));
    }

    public function clearByPrefix ($prefix = ''): void {
        //默认SCAN_NORETRY情况下有可能会返回空数组，设置成SCAN_RETRY，如果是空数组的话，将不返回继续扫描下去
        //BaseRedis::setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY);
        echo 'scan ' . $this->getKey($prefix) . '*' . PHP_EOL;
        $arr_keys = BaseRedis::scan($this->getKey($prefix) . '*');
        if (is_array($arr_keys)) {
            //推荐使用unlink函数，非阻塞删除，删除大key时很好用，但是它需要redis版本>=4.0
            foreach ($arr_keys as $key) {
                BaseRedis::del($key);
            }
        } else {
            BaseRedis::del($arr_keys);
        }
    }

    public function flushDB (): void {
        BaseRedis::flushDB();
    }

    public function __call (string $name, array $arguments) {
        return call_user_func_array([BaseRedis::class, $name], $arguments);
    }
}